<template>
  <view class="u-treeSelect" @touchmove.stop.prevent="() => { }" @click.stop.prevent="() => { }" :style="[customStyle]">
    <view v-if="options.length" :style="advStyle" class="u-treeSelect-column">
      <u-select-column :customStyle="{ flex: '0 0 ' + $u.addUnit(menuWidth), background: '#F4F4F4' }"
        v-model:currentIndex="menu1Index" :activeColor="activeColor" :height="selectHeight" :options="options"
        @clickItem="handleClickFirstOption" />
      <u-select-column v-if="level === 3 && options[menu1Index]"
        :customStyle="{ flex: '0 0 ' + $u.addUnit(menuWidth), background: '#F4F4F4' }" v-model:currentIndex="menu2Index"
        :selectValue="secondSelect" :activeColor="activeColor" :height="selectHeight" :options="secondRenderOption"
        @clickItem="handleClickSecondOption" />
      <u-select-column :selectValue="selectItems" :customStyle="{ flex: 1, background: '#FFFFFF' }" :max="max"
        :activeColor="activeColor" :height="selectHeight" :selectedIcon="selectedIcon" :options="renderOption"
        @clickItem="handleClickItem" />
    </view>
    <view class="u-button-group" v-if="showButton">
      <u-button class="u-button-item" v-for="item in buttonList" :key="item" :plain="item.plain" :type="item.type"
        @click="handleClick(item.buttonType)">{{ item.text }}</u-button>
    </view>
  </view>
</template>

<script lang="js">
/**
   * tree-select 分类选择
 * @property {String | Number} v-model 当前选中项的value值
 * @property {Array[Object]} options 选项数据
 * @property {Number} max 最大可选数
 * @property {String | Number} height 选择内容的高度(内容超出将会滚动)（默认auto）
 * @property {String | Number} menuWidth 菜单宽度默认160rpx
 * @property {String} selectedIcon 选中icon
 * @property {String} activeColor 激活时左边文字和右边对勾图标的颜色
 * @example <u-tree-select v-model="value2" :options="items3" height="200px"></u-tree-select>
 */
import USelectColumn from './selectColumn.vue';
import { useInteraction }  from  '../../utils/useInteraction';
import { isArray }  from  '../../utils';

export default {
  name: "u-tree-select",
  options: {
  // 微信小程序中 options 选项
  multipleSlots: true, //  在组件定义时的选项中启动多slot支持，默认启用
  styleIsolation: "shared",  //  启动样式隔离。当使用页面自定义组件，希望父组件影响子组件样式时可能需要配置。具体配置选项参见：微信小程序自定义组件的样式
  virtualHost: true,  //  将自定义节点设置成虚拟的，更加接近Vue组件的表现。我们不希望自定义组件的这个节点本身可以设置样式、响应 flex 布局等，而是希望自定义组件内部的第一层节点能够响应 flex 布局或者样式由自定义组件本身完全决定
  },
  components: {
    USelectColumn
  },
  props: {
    // 当前选中项的value值
    value: {
        type: [Number, String, Array],
        default: ""
    },
    modelValue: {
        type: [Number, String, Array],
        default: ""
    },
    // 选项数据
    options: {
        type: Array,
        default() {
          return [];
        }
    },
      // 最大可选数
      max: {
        type: Number,
        default: 1
      },
    // 高度
    height: {
        type: [Number, String],
        default: "auto"
    },
    // 菜单宽度默认160rpx
    menuWidth: {
        type: [Number, String],
        default: "160"
    },
    // 选中icon
    selectedIcon: {
        type: String,
        default: "checkbox-mark"
    },
    // 激活时左边文字和右边对勾图标的颜色
    activeColor: {
        type: String,
        default: "#3875FF"
    },
  // 自定义样式，对象形式
  customStyle: {
    type: Object,
    default() {
      return {};
    }
  },
    //是否显示取消和确定
  showButton: {
    type: Boolean,
    default: false,
  },
  // 多选模式下的返回值策略：  ALL |  PARENT |  CHILD
  valueStrategy: {
    type: String,
    default: 'CHILD'
  },
  // 是否显示全部项
  showAll: {
    type: Boolean,
    default: false
  },
  // 全部项的文本
  allText: {
    type: String,
    default: '全部'
  },
  },
  emits: ["update:modelValue", "input", 'selectChild','handleHide'],
  data() {
    return {
      menu1Index: 0,
      menu2Index: 0,
      secondSelect: undefined,
      level: 0,
      selectItems: undefined,
      interaction: {},
      valueEntities: new Map(),
      cacheValue: [],
      buttonList: [
        {
          text: '重置',
          type: 'primary',
          plain: true,
          buttonType: 'cancel'
        },
        {
          text: '确定',
          type: 'primary',
          plain: false,
          buttonType: 'confirm'
        }
      ],
    };
  },
  computed: {
    valueCom() {
      // #ifndef VUE3
      return this.value;
      // #endif

      // #ifdef VUE3
      return this.modelValue;
      // #endif
    },
    // 监听props是否发生了变化
    propsChange() {
      return `${this.options}`;
      },
    selectHeight() {
      return this.showButton ? `${this.height.replace('px','') - 64}px` : this.height;
    },
    advStyle() {
      return this.showButton ? { display: 'flex', width: '100%',flex: 1, minHeight: 0 } : {};
    },
    secondRenderOption() {
      if (this.showAll) {
        return [
          {
            label: this.allText,
            value:  `_$all$_${this.menu1Index}`,
            disabled: false,
            children: []
          },
          ...this.options[this.menu1Index].children,
        ]
      }
      return this.options[this.menu1Index].children;
    },
    renderOption() {
      let options = this.options[this.menu1Index];
      // 如果存在第三层，就会渲染第三层的数据
      if (this.level === 3) {
        options = this.secondRenderOption[this.menu2Index];
      }
      if (this.showAll && options.children.length) {
        return [
          {
            label: this.allText,
            value:  `_$all$_${this.menu1Index}${this.level === 3 ? `-${this.menu2Index}` : ''}`,
            disabled: false,
          },
          ...options.children,
        ]
      }
      return options.children;
    }
  },
  watch: {
      propsChange() {
        // 当值变化时，重新初始化
        if (this.options) this.init();
      },
    menu1Index() {
        this.menu2Index = 0;
    },
      valueCom: {
        immediate:true,
        handler(val) {
          this.formatSelectItems(val);
        }
    },
    selectItems: {
        deep: true,
        handler(val) {
          //显示确定和取消按钮需要通过单击确定和取消迎按钮更新值
      !this.showButton && this.updateValue(val);
        }
    }
  },
  mounted() {
    this.init();
  this.interaction = useInteraction(this.$emit);
  },
  methods: {
    init() {
      // 递归获取配置层数
      let optionLevel = 0;
      // 构建value和option的映射关系
      const valueEntities = new Map();
      this.traversalTreeStructure(this.options, (item, level, parent) => {
        // 最多三层
        if (level <= 3) {
          optionLevel = level;
        }
        // 暂时用解构构建新对象，是否在原有对象上修改待商榷
        valueEntities.set(item.value, {
          ...item,
          level,
          parent,
        });
      });
      this.valueEntities = valueEntities;
      this.level = optionLevel;
    },
    reset() {
      this.selectItems = this.max > 1 ? [] : '';
      this.$emit("input", this.selectItems);
      this.$emit("update:modelValue", this.selectItems);
    },
    handleClick(type) {
      if(type === 'cancel') {
            //重置后当前选中下标为第一项
        this.menu1Index = 0;
            this.menu2Index = 0;
        this.reset();
      } else{
        this.updateValue(this.selectItems);
        this.$emit('handleHide');
      }
    },
    // 格式化选中项的值
    formatSelectItems(value) {
      if (this.valueStrategy !== 'CHILD' && isArray(value)) {
        if (this.valueStrategy === 'ALL') {
          this.selectItems = value?.filter((item => {
            return !this.valueEntities.get(item)?.children
          }));
        } else {
          const parentSet = new Set(),
          parentChildValues = [];
          value.forEach((item) => {
            const node = this.valueEntities.get(item);
            if (node?.children) {
              parentSet.add(node);
            } else {
              parentChildValues.push(item);
            }
          });
          for (let item of parentSet.values()) {
            if (item.children) {
              item.children.forEach((child) => {
                parentSet.add(child);
              });
            } else {
              parentChildValues.push(item.value);
            }
          }
          this.selectItems = parentChildValues;
        }
      } else {
        this.selectItems = value;
      }
    },
    // 比较两个数组是否相等
    isEqualArray(arr1, arr2) {
      if (arr1.length !== arr2.length) {
        return false;
      }
      return arr1.every((item) => arr2.includes(item));
    },
        // 判断是否是字符串
    isString(val) {
      return typeof val === 'string';
    },
    isAllItem(val) {
      return this.isString(val) && val.startsWith('_$all$_');
    },
    // 第一级切换后，清除当前选择内容
    handleClickFirstOption(item,index){
      if(this.menu1Index !== index){
        this.reset();
      }
    },
    // 点击第二列的选项
    handleClickSecondOption(item) {
      // 上次选中的不是全部项或者是全部项，这次选中的是全部项
      if (this.isAllItem(item?.value)) {
        const list = this.secondRenderOption.reduce((pre, cur, index) => {
          if (index !== 0 && cur.children) {
            cur.children.forEach((child) => {
              if (!pre.includes(child.value) && !this.selectItems.includes(child.value)) {
                pre.push(child.value);
              }
            });
          }
          return pre;
        }, []);
        this.selectItems = Array.isArray(this.selectItems) ? [...this.selectItems, ...list] : this.selectItems ? [this.selectItems, ...list] : [...list];
      }
      // 上次选中的是全部项，这次选中的不是全部项
      if (this.isAllItem(this.secondSelect) && !this.isAllItem(item?.value)) {
        this.selectItems = this.selectItems.filter((item) => {
          return item && !this.secondRenderOption.some((option) => {
            return option.children?.some((child) => child.value === item);
          });
        });
      }
      this.secondSelect = item.value;
    },
    updateValue(val) {
      if (isArray(val) && this.isEqualArray(val, this.cacheValue)) {
        return;
      }
      let resultValue = val;
      const { triggerInteraction, closureLinkage } = this.interaction;
      if (val.length) {
        triggerInteraction({
          seriesType: 'uview_treeSelect_page_mobile',
          values: val,
          interactionState: { isLinkage: true },
        })
      } else {
          closureLinkage();
      }
      if (this.max > 1 && isArray(val)) {
        const selectedAll = val.filter((item) => typeof item === 'string' && item.includes('_$all$_'));
        const withOutAll = val.filter((item) => !selectedAll.includes(item));
        if (this.valueStrategy !== 'CHILD') {
          const { parentChildValues, allParents, parents } = this.getFullSelectedNode(withOutAll)
          // 多选模式下，返回包含被完整选中的父节点的选中的值数组
          if (this.valueStrategy === 'ALL') {
            resultValue = [...withOutAll, ...allParents.map((item) => item.value)];
          } else if (this.valueStrategy === 'PARENT') {
            // 多选模式下，①当选中1个父级节点下面的所有子级节点时，只传这个父级节点；②当选中1个父节点下面的部分子节点时，传选中的子节点；
            resultValue = [...withOutAll, ...parents.map((item) => item.value)].filter((item) => !parentChildValues.includes(item));
          }
        } else {
          resultValue = [...withOutAll];
        }
        if (this.showAll && this.level === 3 && this.menu2Index === 0) {
          selectedAll.push(`_$all$_${this.menu1Index}`);
        }
        selectedAll.forEach((item) => {
          const data = item.split('_$all$_')[1];
          let element;
          if (data.includes('-')) {
            const [index1, index2] = data.split('-').map((item) => Number(item));
            element = this.options[index1].children[index2 - 1];
          } else {
            element = this.options[Number(data)];
          }
          if (!resultValue.includes(element.value)) {
            resultValue.push(element.value);
          }
        });
        resultValue = this.unique(resultValue);
        this.cacheValue = [...val];
      }
      // 修改通过v-model绑定的值
      this.$emit("input", resultValue);
      this.$emit("update:modelValue", resultValue);
    },
    // 数组去重
    unique(arr) {
      return Array.from(new Set(arr));
    },
    // 判断是否全选
    checkFullSelected(item, values) {
      return item.children.every((child) => {
        if (values.includes(child.value)) {
          return true;
        }
        return false;
      });
    },
    // 获取完整选中的节点信息
    getFullSelectedNode(selectedValues) {
      // 递归判定完整选中的节点
      let parents = [],
      // 所有完整选中的父节点
        allParents = [],
        // 完整选中的父节点下面的子节点
        parentChildValues = [];
        // 所有相关的父节点set
      const parentSet = new Set()
      selectedValues.forEach((item) => {
        const parent = this.valueEntities.get(item)?.parent;
        if (parent) {
          parentSet.add(this.valueEntities.get(parent.value));
        }
      });
      for (let item of parentSet.values()) {
        if (this.checkFullSelected(item, selectedValues)) {
          parents.push(item);
          allParents.push(item);
          item.children.forEach((child) => {
            parents = parents.filter((parent) => parent.value !== child.value);

            parentChildValues.push(child.value);
          });
          selectedValues.push(item.value);
          if (item.parent) {
            parentSet.add(this.valueEntities.get(item.parent.value));
          }
        }
      }
      return { parents, allParents, parentChildValues };
    },
    handleClickItem(item, index) {
      // 上次选中的不是全部项或者是全部项，这次选中的是全部项
      if (this.isAllItem(item?.value)) {
        const list = this.renderOption.reduce((pre, cur, index) => {
          if (!this.isAllItem(cur.value) && !this.selectItems.includes(cur.value) ) {
            pre.push(cur.value);
          }
          return pre;
        }, []);
        this.selectItems = Array.isArray(this.selectItems) ? [...this.selectItems, ...list] : this.selectItems ? [this.selectItems, ...list] : [...list];
      }else if(this.max > 1){
        !Array.isArray(this.selectItems) && (this.selectItems = [])
        const index = this.selectItems.indexOf(item.value);
        if (index !== -1) {
          this.selectItems.splice(index, 1);
        } else if (this.selectItems.length < this.max) {
          this.selectItems.push(item.value);
        }
      }else{
        this.selectItems = item?.value;
      }
      // 需要先取到值再触发事件，不知道为什么nextTick不管用
      setTimeout(() => {
        this.$emit('selectChild', item, index);
      }, 0);
    },
    // 必要时抽成工具函数
    traversalTreeStructure(
      data,
      handleNode = () => ({}),
      handleLeafNode = () => {},
      level = 0,
      parent = null
    ) {
      if (!isArray(data)) {
        return [];
      }
      level++;
      const filterData = [];
      for (let item of data) {
        // 创建引用对象，用于过滤叶子节点的实现
        const reference = {};
        reference.node = handleNode(item, level, parent);
        if (isArray(item.children)) {
          // 如果有children继续递归
          const result = this.traversalTreeStructure(
            item.children,
            handleNode,
            handleLeafNode,
            level,
            item
          );
          if (result.length) {
            reference.node.children = result;
          }
        } else {
          handleLeafNode(item, reference, level);
        }
        reference.node && filterData.push(reference.node);
      }
      return filterData;
    },
  }
 };
</script>

<style scoped lang="scss">
@import "../../libs/css/style.components.scss";

.u-treeSelect {
  display: flex;
  width: 100%;
  position: relative;

  .u-treeSelect-column {
    display: flex;
    width: 100%;
    position: relative;
  }

  .u-button-group {
    width: 100%;
    display: flex;

    .u-button-item {
      flex: 1;
      line-height: 32px;
      margin: 12px;
    }
  }

  :deep() {
    .u-cell-item-box {
      background: transparent;
    }

    .u-cell {
      line-height: 22px;
      padding: 9px 12px;

      .u-cell_title {
        flex: 1;
      }

      .u-cell__value {
        flex: unset;
      }
    }

    .u-border-bottom:after {
      display: none;
    }

    .u-selectColumn {
      flex: 1
    }
  }
}
</style>
